<template>
    <div class="player" v-show="playlist.length>0">
      <transition name="normal"
                  @enter="enter"
                  @after-enter="afterEnter"
                  @leave="leave"
                  @after-leave="afterLeave"
      >
        <div class="normal-player" v-show="fullScreen">
          <div class="background">
            <img :src="currentSong.image" alt="" width="100%" height="100%">
          </div>
            <div class="top">
              <div class="back" @click="back">
                <i class="icon-back"></i>
              </div>
              <div class="title" v-html="currentSong.name"></div>
              <div class="subtitle" v-html="currentSong.singer"></div>
            </div>
            <div class="middle" @touchstart="middleTouchStart" @touchmove.prevent="middleTouchMove" @touchend.prevent="middleTouchEnd">
              <div class="middle-l" ref="middleL">
                <div class="cd-wrapper" ref="cdWrapper">
                  <div class="cd" :class="cdCls">
                    <img :src="currentSong.image" alt="" class="image">
                  </div>
                </div>
                <div class="playing-lyric-wrapper">
                  <div class="playing-lyric">{{playingLyric}}</div>
                </div>
              </div>
              <scroll class="middle-r" ref="lyricList" :data="currentLyric && currentLyric.lines">
                <div class="lyric-wrapper">
                  <div class="currentLyric">
                    <p ref="lyricLine"
                       class="text"
                       :class="{'current': currentLineNum === index}"
                       v-for="(line,index) in currentLyricLines">
                        {{line.txt}}
                    </p>
                  </div>
                </div>
              </scroll>
            </div>
            <div class="bottom">
              <div class="dot-wrapper">
                <span class="dot" :class="{'active': currentShow === 'cd'}"></span>
                <span class="dot" :class="{'active': currentShow === 'lyric'}"></span>
              </div>
              <div class="progress-wrapper">
                <span class="time time-l">{{format(currentTime)}}</span>
                <div class="progress-bar-wrapper">
                  <progress-bar :percent="percent" @percentChange="onProgressBarChange"></progress-bar>
                </div>
                <span class="time time-r">{{format(currentSong.duration)}}</span>
              </div>
              <div class="operators">
                <div class="icon i-left" @click="changeMode">
                  <i class="icon-sequence" :class="iconMode"></i>
                </div>
                <div class="icon i-left" :class="disableCls">
                  <i class="icon-prev" @click="prev"></i>
                </div>
                <div class="icon i-center" :class="disableCls">
                  <i :class="playIcon" @click="togglePlaying"></i>
                </div>
                <div class="icon i-right" :class="disableCls">
                  <i class="icon-next" @click="next"></i>
                </div>
                <div class="icon i-right">
                  <i class="icon icon-not-favorite"></i>
                </div>
              </div>
            </div>
        </div>
      </transition>
      <transition name="mini">
        <div class="mini-player" v-show="!fullScreen" @click="open">
          <div class="icon">
            <img :src="currentSong.image" alt="" width="40" height="40" :class="cdCls">
          </div>
          <div class="text">
            <h2 class="name" v-html="currentSong.name"></h2>
            <p class="desc" v-html="currentSong.singer"></p>
          </div>
          <div class="control">
            <progress-circle :radius="radius" :percent="percent">
              <i :class="miniIcon" @click.stop="togglePlaying" class="icon-mini"></i>
            </progress-circle>
          </div>
          <div class="control" @click.stop="showPlayList">
              <i class="icon-playlist"></i>
          </div>
        </div>
      </transition>
      <play-list ref="playList"/>
      <audio src="http://dl.stream.qqmusic.qq.com/C4000016j8j527uqHq.m4a?guid=3399144384&vkey=E4E301A9909010D6CF88F353F926345890F6301F0E40FE1F2625EE0B24DDF91DD231A7DF2F39BCEE3BC3B8C320B663F59E1F4744A60303DC&uin=0&fromtag=38" ref="audio" @canplay="ready" @error="error" @timeupdate="updateTime" @end="end"></audio>
    </div>
</template>

<script>
  import {mapGetters, mapMutations} from 'vuex';
  import animations from 'create-keyframe-animation';
  import {prefixStyle} from "common/js/dom";
  import {shuffle} from "common/js/util";
  import progressBar from "base/progress-bar/progress-bar";
  import progressCircle from "base/progress-circle/progress-circle";
  import {playMode} from "../../common/js/config";
  import Lyric from "lyric-parser";
  import scroll from "base/scroll/scroll";
  import playList from '@/components/play-list/play-list';

  const transform = prefixStyle('transform');
  const transitionDuration = prefixStyle('transitionDuration');

  export default {
        name: "player",
      data() {
            return {
              songReady: false, // 只有当歌曲在播放的时候才能切换
              currentTime: 0,
              radius: 32,
              currentLyric: null,
              currentLineNum: 0,// 当前歌词所在的行
              currentShow: 'cd', // 默认展示CD
              playingLyric: '',
              currentLyricLines: []
            }
      },
      created() {
            this.touch ={}
      },
      computed: {
          // fullscreen playlist控制播放
        cdCls() {
          return this.playing ? 'play' : 'play pause'
        },
        playIcon() {
          return this.playing ? 'icon-pause' : 'icon-play'
        },
        miniIcon() {
          return this.playing ? 'icon-pause-mini' : 'icon-play-mini'
        },
        disableCls() {
          return this.songReady ? '' : 'disable'
        },
        percent() {
          return this.currentTime / this.currentSong.duration;
        },
        iconMode() {
          let icon = '';
          if (this.mode === playMode.sequence) {
            icon = 'icon-sequence'
          }
          if (this.mode === playMode.loop) {
            icon = 'icon-loop'
          }
          if (this.mode === playMode.random) {
            icon = 'icon-random'
          }
          return icon;
        },
        ...mapGetters([
          'playlist',
          'fullScreen',
          'currentSong',
          'playing',
          'currentIndex',
          'mode',
          'sequenceList'
        ])
      },
      methods: {
        togglePlaying() {
          if (!this.songReady) {
            return
          }
          this.setPlayingState(!this.playing);
          // 解决暂停时歌词依旧滚动情况
          if (this.currentLyric) {
            this.currentLyric.togglePlay()
          }
        },
        back() {
          // 不能直接修改fullScreen为false 通过mutation改变
          this.setFullScreen(false);
        },
        open() {
          this.setFullScreen(true)
        },
        // el=element元素 ，done执行完后的跳下一个钩子
        enter(el, done) {
          // 首先获取位置
          const {x,y,scale} = this._getPosAndScale();
          let animation = {
            0: {
              transform: `translate3d(${x}px,${y}px,0) scale(${scale})`
            },
            60: {
              transform: `translate3d(0,0,0) scale(1.1)`
            },
            100: {
              transform: `translate3d(0,0,0) scale(1)`
            }
          }
          animations.registerAnimation({
            name: 'move',
            animation,
            presets: {
              duration: 400, // 动画间隔
              easing: 'linear'
            }
          })
          animations.runAnimation(this.$refs.cdWrapper,'move',done) // 参数（DOM,动画,callback）
        },
        afterEnter() {
          animations.unregisterAnimation('move');
          this.$refs.cdWrapper.style.animation = ''
        },
        leave(el, done) {
          this.$refs.cdWrapper.style.transition = 'all 0.4s';
          const {x,y,scale} = this._getPosAndScale()
          this.$refs.cdWrapper.style[transform] = `translate3d(${x}px,${y}px,0) scale(${scale})`
          this.$refs.cdWrapper.addEventListener('transitionend',done)
        },
        afterLeave() {
          this.$refs.cdWrapper.style.transition = '';
          this.$refs.cdWrapper.style[transform] = '';
        },
        next() {
          if (!this.songReady) {
            return;
          }
          if (this.playlist.length === 1) {
            // 歌曲里只有一首
            this.loop();
          } else {
            let index = this.currentIndex + 1;
            if (index === this.playlist.length) {
              index = 0;
            }
            this.setCurrentIndex(index);
            if (!this.playing) {
              this.togglePlaying();
            }
          }

          this.songReady = false;
        },
        prev() {
          if (!this.songReady) {
            return;
          }
          if (this.playlist.length === 1) {
            // 歌曲里只有一首
            this.loop();
          } else {
            let index = this.currentIndex - 1;
            if (index === -1) {
              index = this.playlist.length -1;
            }
            this.setCurrentIndex(index);
            if (!this.playing) {
              this.togglePlaying();
            }
          }
          this.songReady = false;
        },
        ready() {
          this.songReady = true;
        },
        error() {
          this.songReady = true; // 保证正常使用
          console.log('播放失败')
        },
        updateTime(e) {
          this.currentTime = e.target.currentTime;
        },
        format(interval) {
          interval = interval | 0; // 正数的向下取整 == Math.floor
          const minutie = interval / 60 | 0;
          const second = this._pad(interval % 60);
          return `${minutie}:${second}`
        },
        changeMode() {
          const mode = (this.mode + 1) % 3;
          console.log(mode)
          this.setPlayMode(mode);
          let list = null;
          if (mode === playMode.random) {
              // 随机播放
              list = shuffle(this.sequenceList);
              console.log('乱序'+list);
          } else {
            // 顺序播放或者列表播放
            list = this.sequenceList;
            console.log('顺序'+list)
          }
          this.resetCurrentIndex(list);
          this.setPlayList(list);
        },
        // 当更改播放模式时 当前音乐不会被改变
        resetCurrentIndex(list) {
          // 根据this.currentSong.id 对应所在的索引 返回索引
          let index = list.findIndex((item) => {
            return item.id === this.currentSong.id
          });
          this.setCurrentIndex(index);
        },
        end() {
          if (this.mode === playMode.loop) {
            // 单曲循环
            this.loop();
          } else {
            // 播放完时自动播放下一首
            this.next();
          }
        },
        loop() {
          // 单曲循环 设置当前时间为0
          this.$refs.audio.currentTime = 0;
          this.$refs.audio.currentTime.play();
          if (this.currentLyric) {
            this.currentLyric.seek(0);
          }
        },
        onProgressBarChange(percent) {
          const currentTime = this.currentSong.duration * percent
          this.$refs.audio.currentTime = currentTime
          if (!this.playing) {
            this.togglePlaying()
          }
          // 歌词显示到拖动的时间位
          if (this.currentLyric) {
            this.currentLyric.seek(currentTime * 1000)
          }
        },
        getLyric() {
          this.currentSong.getLyric().then((lyric) => {
            // this.currentLyric.lines = [];
            this.currentLyric = new Lyric(lyric,this.handleLyric); // this.handleLyric 接受的一个回调函数
            this.currentLyricLines = this.currentLyric.lines;
            if (this.playing) {
              this.currentLyric.play();
            }
          }).catch(() => {
            this.currentLyric = null;
            this.playingLyric = '';
            this.currentLineNum = 0;
          })
        },
        //  handleLyric函数接受两个参数
        handleLyric({lineNum,txt}) {
          this.currentLineNum = lineNum;
          // 歌词滚动超过五行的时候就让高亮的位置居中显示
          if (lineNum > 5) {
            let linEL = this.$refs.lyricLine[lineNum - 5];
            this.$refs.lyricList.scrollToElement(linEL, 1000)
          } else {
            this.$refs.lyricList.scrollTo(0, 0, 1000)
          }
          // 在cd页播放展示的歌词
          this.playingLyric = txt;
        },
        middleTouchStart(e) {
          this.touch.inintiated = true;
          const touch = e.touches[0];
          // touch.pageX 触点相对于HTML文档左边沿的的X坐标. 当存在水平滚动的偏移时, 这个值包含了水平滚动的偏移
          this.touch.startX = touch.pageX;
          this.touch.startY = touch.pageY;
        },
        middleTouchMove(e) {
          if (!this.touch.inintiated) {
            return
          }
          const touch = e.touches[0];
          const deltaX = touch.pageX - this.touch.startX;
          const deltaY = touch.pageY - this.touch.startY;
          // 如果横轴的偏移大于众轴的偏移 认为它是众向滚动
          if (Math.abs(deltaY) > Math.abs(deltaX)) {
            // 上下滚动歌词的时候
            return
          }
          const left = this.currentShow === 'cd' ? 0 : -window.innerWidth; // 如果是在CD页记录起始位为0 另一边就是-屏幕宽带
          const offsetWidth = Math.min(0,Math.max(-window.innerWidth, left + deltaX));
          this.touch.percent = Math.abs(offsetWidth / window.innerWidth);  // 获取滚动所占屏幕的百分比
          this.$refs.lyricList.$el.style[transform] = `translate3d(${offsetWidth}px,0,0)`; // 滑动偏移量
          this.$refs.lyricList.$el.style[transitionDuration] = 0; // 偏移动画
          this.$refs.middleL.style.opacity = 1 - this.touch.percent; // this.touch.percent百分比越大透明度越小
          this.$refs.middleL.style[transitionDuration] = 0;
        },
        middleTouchEnd() {
          let offsetWidth;
          let opacity
          // 从右往左滑
          if (this.currentShow === 'cd') {
            if (this.touch.percent > 0.1) {
              // 滑动超过10%
              offsetWidth = -window.innerWidth;
              opacity = 0;
              this.currentShow = 'lyric';
            } else {
              opacity = 1;
              offsetWidth = 0
            }
          } else {
            // 从左往右滑
            if (this.touch.percent < 0.9) {
              offsetWidth = 0;
              this.currentShow = 'cd';
              opacity = 1;
            } else {
              offsetWidth = -window.innerWidth;
              opacity = 0;
            }
          }
          const time = 300;
          this.$refs.lyricList.$el.style[transform] = `translate3d(${offsetWidth}px,0,0)`; // 滑动偏移量
          this.$refs.lyricList.$el.style[transitionDuration] = `${time}ms`;
          this.$refs.middleL.style.opacity = opacity;
          this.$refs.middleL.style[transitionDuration] = `${time}ms`;
        },
        showPlayList() {
          this.$refs.playList.show();

        },
        _pad(num, n=2) {
          let len = num.toString().length;
          while (len < n) {
            num = '0' + num;
            len++
          }
          return num
        },
        _getPosAndScale() {
          const targetWidth = 40;
          const paddingLeft = 40;
          const paddingBottom = 30;
          const paddingTop= 80;
          const width= window.innerWidth * 0.8;
          const scale = targetWidth/width;
          const x = -(window.innerWidth/2 - paddingLeft);
          const y = window.innerHeight - paddingTop - width/2 -paddingBottom;
          return {
            x,
            y,
            scale
          }
        },
        ...mapMutations({
          setFullScreen: 'SET_FULL_SCREEN',
          setPlayingState: 'SET_PLAYING_STATE',
          setCurrentIndex: 'SET_CURRENT_INDEX',
          setPlayMode: 'SET_PLAY_MODE',
          setPlayList: 'SET_PLAYLIST'
        })
      },
      watch: {
         currentSong(newSong,oldSong) {
           // 删除最后一首歌曲时不再监听
           if (!newSong.id) {
             return
           }
           // 暂停中切换播放模式时 当前音乐会自动播放
           if (newSong.id === oldSong.id) {
             return
           }
           // 解决来回切换歌曲 歌词不规则跳动
           if (this.currentLyric) {
             this.currentLyric.stop()
           }
           // 观察currentSong数据变化
           clearTimeout(this.timer)
           this.timer = setTimeout(() => {
             this.$refs.audio.play();
             this.getLyric();
           }, 1000)
         },
        playing(newPlaying) {
           const audio = this.$refs.audio;
           this.$nextTick(() => {
             newPlaying ? audio.play() : audio.pause()
           })
        }
      },
      components: {
        progressBar,
        progressCircle,
        scroll,
        playList
      }
    }
</script>

<style scoped lang="stylus" rel="stylesheet/stylus">
  @import "~common/stylus/variable"
  @import "~common/stylus/mixin"

  .player
    .normal-player
      position: fixed
      left: 0
      right: 0
      top: 0
      bottom: 0
      z-index: 150
      background: $color-background
      .background
        position: absolute
        left: 0
        top: 0
        width: 100%
        height: 100%
        z-index: -1
        opacity: 0.6
        filter: blur(20px)
      .top
        position: relative
        margin-bottom: 25px
        .back
          position absolute
          top: 0
          left: 6px
          z-index: 50
          .icon-back
            display: block
            padding: 9px
            font-size: $font-size-large-x
            color: $color-theme
            transform: rotate(-90deg)
        .title
          width: 70%
          margin: 0 auto
          line-height: 40px
          text-align: center
          no-wrap()
          font-size: $font-size-large
          color: $color-text
        .subtitle
          line-height: 20px
          text-align: center
          font-size: $font-size-medium
          color: $color-text
      .middle
        position: fixed
        width: 100%
        top: 80px
        bottom: 170px
        white-space: nowrap
        font-size: 0
        .middle-l
          display: inline-block
          vertical-align: top
          position: relative
          width: 100%
          height: 0
          padding-top: 80%
          .cd-wrapper
            position: absolute
            left: 10%
            top: 0
            width: 80%
            height: 100%
            .cd
              width: 100%
              height: 100%
              box-sizing: border-box
              border: 10px solid rgba(255, 255, 255, 0.1)
              border-radius: 50%
              &.play
                animation: rotate 20s linear infinite
              &.pause
                animation-play-state: paused
              .image
                position: absolute
                left: 0
                top: 0
                width: 100%
                height: 100%
                border-radius: 50%

          .playing-lyric-wrapper
            width: 80%
            margin: 30px auto 0 auto
            overflow: hidden
            text-align: center
            .playing-lyric
              height: 20px
              line-height: 20px
              font-size: $font-size-medium
              color: $color-text-l
        .middle-r
          display: inline-block
          vertical-align: top
          width: 100%
          height: 100%
          overflow: hidden
          .lyric-wrapper
            width: 80%
            margin: 0 auto
            overflow: hidden
            text-align: center
            .text
              line-height: 32px
              color: $color-text-l
              font-size: $font-size-medium
              &.current
                color: $color-text
      .bottom
        position: absolute
        bottom: 50px
        width: 100%
        .dot-wrapper
          text-align: center
          font-size: 0
          .dot
            display: inline-block
            vertical-align: middle
            margin: 0 4px
            width: 8px
            height: 8px
            border-radius: 50%
            background: $color-text-l
            &.active
              width: 20px
              border-radius: 5px
              background: $color-text-ll
        .progress-wrapper
          display: flex
          align-items: center
          width: 80%
          margin: 0px auto
          padding: 10px 0
          .time
            color: $color-text
            font-size: $font-size-small
            flex: 0 0 30px
            line-height: 30px
            width: 30px
            &.time-l
              text-align: left
            &.time-r
              text-align: right
          .progress-bar-wrapper
            flex: 1
        .operators
          display: flex
          align-items: center
          .icon
            flex: 1
            color: $color-theme
            &.disable
              color: $color-theme-d
            i
              font-size: 30px
          .i-left
            text-align: right
          .i-center
            padding: 0 20px
            text-align: center
            i
              font-size: 40px
          .i-right
            text-align: left
          .icon-favorite
            color: $color-sub-theme
      &.normal-enter-active, &.normal-leave-active
        transition: all 0.4s
        .top, .bottom
          transition: all 0.4s cubic-bezier(0.86, 0.18, 0.82, 1.32)
      &.normal-enter, &.normal-leave-to
        opacity: 0
        .top
          transform: translate3d(0, -100px, 0)
        .bottom
          transform: translate3d(0, 100px, 0)
    .mini-player
      display: flex
      align-items: center
      position: fixed
      left: 0
      bottom: 0
      z-index: 180
      width: 100%
      height: 60px
      background: $color-highlight-background
      &.mini-enter-active, &.mini-leave-active
        transition: all 0.4s
      &.mini-enter, &.mini-leave-to
        opacity: 0
      .icon
        flex: 0 0 40px
        width: 40px
        padding: 0 10px 0 20px
        img
          border-radius: 50%
          &.play
            animation: rotate 10s linear infinite
          &.pause
            animation-play-state: paused
      .text
        display: flex
        flex-direction: column
        justify-content: center
        flex: 1
        line-height: 20px
        overflow: hidden
        .name
          margin-bottom: 2px
          no-wrap()
          font-size: $font-size-medium
          color: $color-text
        .desc
          no-wrap()
          font-size: $font-size-small
          color: $color-text-d
      .control
        flex: 0 0 30px
        width: 30px
        padding: 0 10px
        .icon-play-mini, .icon-pause-mini, .icon-playlist
          font-size: 30px
          color: $color-theme-d
        .icon-mini
          font-size: 32px
          position: absolute
          left: 0
          top: 0

  @keyframes rotate
    0%
      transform: rotate(0)
    100%
      transform: rotate(360deg)
</style>
